/*------------------------------------------------------------------------------

Publication: Hakhverdian, A. and Schakel, W. (2021) 'The Political
	Representation of Left-Nationalist Voters', Acta Politica, online first
	(https://doi.org/10.1057/s41269-021-00205-8).

Description: This do-file contains the data preparation, analysis and figures to
	replicate all results in Hakhverdian and Schakel (2021).

Sections:
	1. Preparation
	2. Analysis
	3. Figures

Data: Dutch Parliamentary Election Studies (Version 1.5), downloaded in June
	2021 from: https://doi.org/10.17026/dans-xby-5dhs

Last updated: 14 June 2021

------------------------------------------------------------------------------*/

global dpes "YOUR PATH HERE"

use "$dpes\DPES 2017 v1.5.dta", clear

/*------------------------------------------------------------------------------
 1. Preparation
------------------------------------------------------------------------------*/

* First we recode a number of existing variables in the DPES, starting with the
* dependent variables

* Political trust
recode S049 S050 S056 (1 = 4) (2 = 3) (3 = 2) (4 = 1) (997/999 = .),		///
	gen(tr1 tr2 tr3)
gen trust = (tr1 + tr2 + tr3) / 3

* Political cynicism (we don't use four items that have many missing values and
* are dichotomous - V252, V254, V256 and V257)
recode V260 V262 V322 (994/999 = .), gen(cyn1 cyn2 cyn3)
recode V261 V263 V321 V323 V326 V330 (1 = 5) (2 = 4) (4 = 2) (5 = 1)		///
	(994/999 =.), gen(cyn4 cyn5 cyn6 cyn7 cyn8 cyn9)
egen polcyn = rowmean(cyn1 - cyn9)
egen cynmiss = rowmiss(cyn1 - cyn9)
replace polcyn = . if cynmiss > 5 // we drop respondents with >5 missing scores

* Satisfaction with democracy
recode V240 (1 = 4) (2 = 3) (3 = 2) (4 = 1) (994/999 = .), gen(satdem)
recode satdem (1 2 = 0) (3 4 = 1), gen(satdem01) // used for Figure 2

* Direct democracy preferences (we don't use V312, V313 or V314 because they
* have many missing values)
recode V311 V310 (1 = 5) (2 = 4) (4 = 2) (5 = 1) (994/999 = .), gen(dir1 dir2)
recode V315 (2 = 1) (1 = 5) (3 = 3) (994/999 = .), gen(dir3)
egen dd = rowmean(dir1 dir2 dir3)

* Suitable party (see fn. 1 and Appendix Table 10)
recode S180 (2 = 0) (997/999 = .), gen(party)

* Congruence (see fn. 1 and Appendix Table 10)
recode V244 (1 2 = 1) (3 4 = 0) (994/999 = .), gen(cong)

* Weight (the weighting variable has a number of missing values, which we give a
* weight of 1)
gen weight = WgtJ
replace weight = 1 if weight == .

*-------------------------------------------------------------------------------

* Next, we turn to the main independent variables - the ideological quadrants

* Cultural attitudes
recode V143 (4 = 1) (3 = 2) (2 = 3) (1 = 4) (99/max = .), gen(ctemp1)
recode S156 S157 (5 = 1) (4 = 2) (3 = 3) (2 = 4) (1 = 5) (99/max = .),		///
	gen(ctemp2 ctemp3)
recode V146 S155 (99/max = .), gen(ctemp4 ctemp5)

* Economic attitudes
recode S052 (4 = 1) (3 = 2) (2 = 3) (1 = 4) (99/max = .), gen(etemp1)
recode S132 V147 V144 (99/max = .), gen(etemp2 etemp3 etemp4)
recode V098 (7 = 1) (6 = 2) (5 = 3) (4 = 4) (3 = 5) (2 = 6) (1 = 7)			///
	(99/max = .), gen(etemp5)

* All items are standardized
forval i = 1/5 {
	egen cult`i' = std(ctemp`i')
	egen econ`i' = std(etemp`i')
}

gen cult = (cult1 + cult2 + cult3 + cult4 + cult5) / 5
gen econ = (econ1 + econ2 + econ3 + econ4 + econ5) / 5

* This loop gives respondents a relative rank from 0 to 1 on the cultural and
* economic dimensions
foreach dim in cult econ {
	sort `dim' RNR
	sum `dim'
	replace `dim' = _n / r(N) if `dim' != .
}

* Now we can make the quadrants
gen quad = .
replace quad = 1 if cult > .55 & econ < .45 & cult != . & econ != .
replace quad = 2 if cult > .55 & econ > .55 & cult != . & econ != .
replace quad = 3 if cult < .45 & econ < .45 & cult != . & econ != .
replace quad = 4 if cult < .45 & econ > .55 & cult != . & econ != .
replace quad = 0 if (cult >= .45 & cult <= .55) | (econ >= .45 & econ <= .55)

label define quad 1 "Left-nationalist" 2 "Right-nationalist"				///
	3 "Left-cosmopolitan" 4 "Right-cosmopolitan" 0 "Center", replace
label values quad quad

* Alternative quadrants (see Appendix Tables 7-9)
recode S132 (994/999 = .), gen(redist)
recode S156 (1 = 5) (2 = 4) (4 = 2) (5 = 1) (994/999 = .), gen(threat)

gen quad_alt = .
replace quad_alt = 1 if threat > 3 & redist < 3 & threat != . & redist != .
replace quad_alt = 2 if threat > 3 & redist > 3 & threat != . & redist != .
replace quad_alt = 3 if threat < 3 & redist < 3 & threat != . & redist != .
replace quad_alt = 4 if threat < 3 & redist > 3 & threat != . & redist != .
replace quad_alt = 0 if threat == 3 | redist == 3

* Dichotomous versions of alternative quadrants (used for Table 1)
recode redist threat (1 2 = 1) (3 = 2) (4 5 = 3), gen(redist01 threat01)
label values quad_alt quad

* City block distances (see Figure 1)
recode V163 (9 = 8) (8 10/996 = .), gen(vote)
recode V090-V098 (994/999=.), gen(inc3 inc2 inc8 inc1 inc5 inc6 inc7 inc4 inc0)
recode V110-V118 (994/999=.), gen(cul3 cul2 cul8 cul1 cul5 cul6 cul7 cul4 cul0)

* The loop below calculates the distance between each citizen and the party they
* voted for, parliament and the coalition for the issues of income inequality
* and integration
quietly foreach v of newlist inc cul {
	gen `v'part = .
	
	forval i = 1/8 {
		sum `v'`i' [aw = weight]
		replace `v'`i' = `r(mean)'
		replace `v'part = `v'`i' if vote == `i'
	}

	* Parties are weighted by seats
	gen `v'parl = (41 * `v'3 + 38 * `v'2 + 15 * `v'8 + 15 * `v'5 +			///
	13 * `v'1 + 12 * `v'6 + 5 * `v'7 + 4* `v'8) / 150
	gen `v'coal = (41 * `v'3 + 38 * `v'2)/79

	gen `v'distpart = abs(`v'0 - `v'part)
	gen `v'distparl = abs(`v'0 - `v'parl)
	gen `v'distcoal = abs(`v'0 - `v'coal)
}

gen cbdpart = incdistpart + culdistpart
gen cbdparl = incdistparl + culdistparl
gen cbdcoal = incdistcoal + culdistcoal

*-------------------------------------------------------------------------------

* Finally we add a number of control variables

* Income
egen income = cut(D009) if D009 < 999992, group(5)
replace income = income + 1
replace income = D008 if D008 < 99

* Social class (self-identified)
recode V353 (1 = 5) (2 = 4) (4 = 2) (5 = 1) (994/999 = .), gen(class)
recode V353 (4 5 = 1) (1/3 = 0) (994/999 = .), gen(wclass)

* Age
gen age = V012 if V012 != 996

* Urbanization
recode D005 (1 = 5) (2 = 4) (4 = 2) (5 = 1) (999 = .), gen(urban)

* Education
recode V368 (1/3 = 1) (4 5 = 2) (6 = 3) (7/8 = 4) (9/999 = .), gen(edu)
recode edu (2/4 = 0), gen(lowed)
recode edu (1/3 = 0) (4 = 1), gen(highed)

* Sex
recode V010 (1 = 0) (2 = 1) (996 = .), gen(woman)

* Migration background
recode D002 (1 = 0) (2 3 = 1) (999 = .), gen(migr)

* Religiosity
recode V350 (2 = 0) (994/999 = .), gen(relig)

* Political knowledge
gen know1 = (V192 == 2)
gen know2 = (V193 == 9)
gen know3 = (V194 == 3)
gen know4 = (V195 == 3)
gen know5 = (V196 == 1)
gen know = know1 + know2 + know3 + know4 + know5

* Coalition voting
recode V071 (2 3 = 1) (1 4/14 = 0) (993/996 = .), gen(coalvote)
replace coalvote = 0 if V070 == 2

* We drop all variables that were created but are not needed anymore
drop tr1-tr3 cyn* dir* ctemp1-econ redist threat vote-culdistcoal know1-know5

* Labeling variables
label var trust "Political trust (index)"
label var polcyn "Political cynicism (index)"
label var satdem "Satisfaction with democracy"
label var satdem01 "Satisfaction with democracy (dichotomous)"
label var dd "Direct democracy preferences"
label var party "Suitable party"
label var cong "Congruence"
label var weight "Post-stratification weight"

label var quad "Ideological quadrant"
label var quad_alt "Ideological quadrant (two items)"
label var redist01 "Redistributive preferences (dichotomous)"
label var redist01 "Perceived threat by migrants (dichotomous)"
label var cbdpart "City block distance from own party"
label var cbdparl "City block distance from parliament"
label var cbdcoal "City block distance from coalition"

label var income "Income (quintiles)"
label var class "Social class (self-identified)"
label var wclass "Working class (dummy)"
label var age "Age"
label var urban "Urbanization"
label var edu "Education (four levels)"
label var lowed "Low education (dummy)"
label var highed "High education (dummy)"
label var woman "Woman (dummy)"
label var migr "Migrant (dummy)"
label var relig "Religious (dummy)"
label var know "Political knowledge (index)"
label var coalvote "Voted for coalition (dummy)"

/*------------------------------------------------------------------------------
 2. Analysis
------------------------------------------------------------------------------*/

* Main text

* Table 1
tab threat01 redist01 [aw = weight], cell nofreq

* Table 2
reg trust i.quad if !missing(edu, income, class, urban, relig, migr,		///
	coalvote) [pw = weight]
reg trust i.quad income class age urban know i.edu woman migr relig			///
	coalvote [pw = weight]

reg polcyn i.quad if !missing(edu, income, class, urban, relig, migr,		///
	coalvote) [pw = weight]
reg polcyn i.quad income class age urban know i.edu woman migr relig		///
	coalvote [pw = weight]

* Table 3
ologit satdem i.quad if !missing(edu, income, class, urban, relig, migr,	///
	coalvote) [pw = weight], or
ologit satdem i.quad income class age urban know i.edu woman migr relig		///
	coalvote [pw = weight], or

* Table 4
reg dd i.quad if !missing(edu, income, class, urban, relig, migr, coalvote)	///
	[pw = weight]
reg dd i.quad income class age urban know i.edu woman migr relig coalvote	///
	[pw = weight]
reg dd i.quad income class age urban know i.edu woman migr relig coalvote	///
	trust polcyn satdem [pw = weight]

*-------------------------------------------------------------------------------

* Appendix

* Table 6
quietly tabstat lowed highed wclass woman migr relig age income urban		///
	[aw = weight] if quad == 1, stat(mean) save
matrix t6a = r(StatTotal)'
quietly tabstat lowed highed wclass woman migr relig age income urban		///
	[aw = weight], stat(mean) save
matrix t6 = [t6a, r(StatTotal)']
matrix colnames t6 = left-nationalist full_sample
matrix list t6, f(%9.3f)

* Table 7
reg trust i.quad_alt if !missing(edu, income, class, urban, relig, migr,	///
	coalvote) [pw = weight]
reg trust i.quad_alt income class age urban know i.edu woman migr relig		///
	coalvote [pw = weight]

reg polcyn i.quad_alt if !missing(edu, income, class, urban, relig, migr,	///
	coalvote) [pw = weight]
reg polcyn i.quad_alt income class age urban know i.edu woman migr relig	///
	coalvote [pw = weight]

* Table 8
ologit satdem i.quad_alt if !missing(edu, income, class, urban, relig,		///
	migr, coalvote) [pw = weight], or
ologit satdem i.quad_alt income class age urban know i.edu woman migr relig	///
	coalvote [pw = weight], or

* Table 9
reg dd i.quad_alt if !missing(edu, income, class, urban, relig, migr,		///
	coalvote) [pw = weight]
reg dd i.quad_alt income class age urban know i.edu woman migr relig		///
	coalvote [pw = weight]
reg dd i.quad_alt income class age urban know i.edu woman migr relig		///
	coalvote trust polcyn satdem [pw = weight]

* Table 10
logistic cong i.quad if !missing(edu, income, class, urban, relig, migr,	///
	coalvote) [pw = weight]
logistic cong i.quad income class age urban know i.edu woman migr relig		///
	coalvote [pw = weight]

logistic party i.quad if !missing(edu, income, class, urban, relig, migr,	///
	coalvote) [pw = weight]
logistic party i.quad income class age urban know i.edu woman migr relig	///
	coalvote [pw = weight]

/*------------------------------------------------------------------------------
 3. Figures
------------------------------------------------------------------------------*/

* Figure 1: City block distance by quadrant

quietly tabstat cbdpart cbdparl cbdcoal [aw = weight], s(mean) by(quad) save
matrix meancbd = (r(Stat1), r(Stat2), r(Stat3), r(Stat4), r(Stat5))'
svmat meancbd

quietly tabstat cbdpart cbdparl cbdcoal [aw = weight], s(sem) by(quad) save
matrix semcbd = (r(Stat1), r(Stat2), r(Stat3), r(Stat4), r(Stat5))'
svmat semcbd

gen lci_cbd = meancbd1 - 1.96 * semcbd1
gen hci_cbd = meancbd1 + 1.96 * semcbd1

egen cbd = seq(), from(1) to(3) block(1)
egen quadcbd = seq(), from(0) to(4) block(3)
label values quadcbd quad

gen n = _n in 1/15
recode n (4 = 5) (5 = 6) (6 = 7) (7 = 9) (8 = 10) (9 = 11) (10 = 13)		///
	(11 = 14) (12 = 15) (13 = 17) (14 = 18) (15 = 19)

twoway (bar meancbd1 n if cbd == 1, fc(gs6) fi(100) lc(gs6))				///
	(bar meancbd1 n if cbd == 2, fc(gs13) fi(100) lc(gs13))					///
	(bar meancbd1 n if cbd == 3, fc(gs9) fi(100) lc(gs9))					///
	(rcap lci_cbd hci_cbd n, lc(black) msize(zero)),						///
	xt("") yt("City block distance", size(medium))							///
	xlab(2(4)18 2 "Middle" 6 `""Left-" "nationalist""'						///
	10 `""Right-" "nationalist""' 14 `""Left-" "cosmopolitan""'				///
	18 `""Right-" "cosmopolitan""', labgap(tiny) notick)					///
	ylab(0(1)4, angle(hor) nogrid)											///
	legend(order(1 "Own party" 2 "Parliament" 3 "Coalition") r(1) symx(10))	///
	plotr(m(4 4 0 0)) graphr(m(medsmall) fc(white) lc(white))

drop meancbd1-n

*-------------------------------------------------------------------------------

* Figure 2: Predicted evaluations of representative democracy by quadrant

* 2a (Political trust)
quietly reg trust i.quad i.edu income class urban woman relig age migr know	///
	coalvote [pw = weight]
quietly margins, at(quad = (0(1)4)) atmeans
marginsplot, recast(bar) xlab(0(1)4 0 "Middle" 1 `""Left-" "nationalist""'	///
	2 `""Right-" "nationalist""' 3 `""Left-" "cosmopolitan""'				///
	4 `""Right-" "cosmopolitan""') ylab(1(.5)3, ang(hor) nogrid) xt("")		///
	yt("") title("(a) Political trust", c(gs0) siz(large))					///
	plotop(barw(.7) fc(gs11) fi(100) lc(gs11) lw(none))						///
	ciop(lc(gs0) msiz(zero)) plotr(m(sides))								///
	graphr(m(2 2 2 2) lc(gs16) fc(gs16)) name(f2a, replace) nodraw

* 2b (Political cynicism)
quietly reg polcyn i.quad i.edu income class urban woman relig age migr		///
	know coalvote [pw = weight]
quietly margins, at(quad = (0(1)4)) atmeans
marginsplot, recast(bar) xlab(0(1)4 0 "Middle" 1 `""Left-" "nationalist""'	///
	2 `""Right-" "nationalist""' 3 `""Left-" "cosmopolitan""'				///
	4 `""Right-" "cosmopolitan""') ylab(1(1)4, ang(hor) nogrid) xt("")		///
	yt("") title("(b) Political cynicism", c(gs0) siz(large))				///
	plotop(barw(.7) fc(gs11) fi(100) lc(gs11) lw(none))						///
	ciop(lc(gs0) msiz(zero)) plotr(m(sides))								///
	graphr(m(2 2 2 2) lc(gs16) fc(gs16)) name(f2b, replace) nodraw

* 2c (Satisfied with democracy)
quietly logit satdem01 i.quad i.edu income class urban woman relig age migr	///
	know coalvote [pw = weight]
quietly margins, at(quad = (0(1)4)) atmeans
marginsplot, recast(bar) xlab(0(1)4 0 "Middle" 1 `""Left-" "nationalist""'	///
	2 `""Right-" "nationalist""' 3 `""Left-" "cosmopolitan""'				///
	4 `""Right-" "cosmopolitan""') ylab(0(.2)1, ang(hor) nogrid) xt("")		///
	yt("") title("(c) Satisfied with democracy", c(gs0) siz(large))			///
	plotop(barw(.7) fc(gs11) fi(100) lc(gs11) lw(none))						///
	ciop(lc(gs0) msiz(zero)) plotr(m(sides))								///
	graphr(m(2 2 2 2) lc(gs16) fc(gs16)) name(f2c, replace) nodraw

* 2d (Direct democracy preferences)
quietly reg dd i.quad income class age urban know i.edu woman migr relig	///
	coalvote [pw = weight]
quietly margins, at(quad = (0(1)4)) atmeans
marginsplot, recast(bar) xlab(0(1)4 0 "Middle" 1 `""Left-" "nationalist""'	///
	2 `""Right-" "nationalist""' 3 `""Left-" "cosmopolitan""'				///
	4 `""Right-" "cosmopolitan""') ylab(1(1)4, ang(hor) nogrid) xt("")		///
	yt("") title("(d) Direct democracy preferences", c(gs0) siz(large))		///
	plotop(barw(.7) fc(gs11) fi(100) lc(gs11) lw(none))						///
	ciop(lc(gs0) msiz(zero)) plotr(m(sides))								///
	graphr(m(2 2 2 2) lc(gs16) fc(gs16)) name(f2d, replace) nodraw

* Combined
graph combine f2a f2b f2c f2d, graphr(m(0 0 0 0) lc(white) fc(white))		///
	xsize(12) ysize(8) scale(.8)
